// code2
package main

import (
	"fmt"
)

type BracketStack struct {
	values []byte
}

func (self *BracketStack) push(v byte) {
	if self.values == nil {
		self.values = make([]byte, 0, 10)
	}
	self.values = append(self.values, v)
}
func (self *BracketStack) top() byte {
	n := len(self.values)
	return self.values[n-1]
}
func (self *BracketStack) pop() byte {
	n := len(self.values)

	v := self.values[n-1]
	self.values = self.values[:n-1]
	return v
}

type DrCode struct {
	moduleName string
	tokens     []string //用于存放原始码
	tokenList  []string //用于处理过程中的变动列表
	bStack     BracketStack
}

func NewCode(tokens []string, name string) *DrCode {
	code := new(DrCode)
	code.tokens = tokens
	code.moduleName = name
	return code
}
func (code *DrCode) TokenForward() string {
	result := code.tokenList[0]
	code.tokenList = code.tokenList[1:]
	return result
}

//返回一个模块对象
func (code *DrCode) ProcessModule(interp *Interpreter) *DrModule {
	module := new(DrModule)
	module.members = make(map[string]IObject)
	module.Type = TypeModule
	module.name = code.moduleName

	//开始解析
	code.tokenList = code.tokens
	//start := 0
	for index := 0; index < 10; index++ {
		if len(code.tokenList) < 2 {
			break
		}
		var symbol string

		for i := 0; i < len(code.tokenList); i++ { //绕过那些换行符
			symbol = code.tokenList[i]
			if symbol != "\n" {
				code.tokenList = code.tokenList[i:]
				break
			}
		}
		if symbol == "import" {
			code.TokenForward()
			tokens, i := code.GetLine(code.tokenList)
			code.tokenList = code.tokenList[i:]
			for _, each := range tokens {
				if each == "," {
					continue
				}
				source := NewSource(each + ".drg")
				code := NewCode(source.tokens, source.module)
				module2 := code.ProcessModule(interp)
				module.members[source.module] = module2
			}

			//应该开启一个ProcessModule来执行
		} else if symbol == "def" {
			code.TokenForward()
			func0 := code.ProcessFunc()
			//fmt.Println("\n===================打印函数")
			//func0.Print()
			func0.module = module
			module.members[func0.Name] = func0
		} else {
			mainFunc := new(DrFunction)
			//fmt.Println("正在进入当前模块:", code.moduleName)
			mainFunc.Clauses = code.CollectClauses()
			//fmt.Println("\n===================打印语句")
			//for _, cl := range mainFunc.Clauses {
			//	fmt.Println()
			//	cl.Print()
			//}

			mainFunc.Type = TypeUserFunc
			mainFunc.module = module

			if module.members["main"] == nil {
				module.members["main"] = mainFunc
			} else {
				fff := module.members["main"].(*DrFunction)
				fff.Clauses = append(fff.Clauses, mainFunc.Clauses...)
			}
			//fmt.Println("\n离开模块:", code.moduleName)
		}
		//start += 1
	}
	return module
}
func (code *DrCode) CheckName(name string) {
	if !IsValidVarName(name) {
		//fmt.Println("Invalid function name:", name)
		panic("Invlid function or variable name:" + name)
	} else {
		//fmt.Println("A valid function or variable name:", name)
	}
}

//处理函数中的代码
func (code *DrCode) ProcessFunc() *DrFunction {

	function := new(DrFunction)
	function.Type = TypeUserFunc
	//get the function Name，获取函数名
	name := code.TokenForward()
	code.CheckName(name)
	function.Name = name
	brace := code.TokenForward()
	if brace != "(" {
		panic("'(' is required after the function name")
	} else {
		//fmt.Println("(")
	}
	//get the parameters 获取参数
	for {
		paraName := code.TokenForward()
		if paraName == ")" {
			//fmt.Println("end parameters")
			break
		}
		if paraName == "," {
			continue
		}
		code.CheckName(paraName)
		function.AddParaName(paraName)

	}
	//get the '{'  获得第一个括号，开始函数体处理
	symbol := code.TokenForward()
	for { //绕过那些换行符
		if symbol == "\n" {
			symbol = code.TokenForward()
		} else {
			break
		}
	}
	if symbol == "{" {
		//fmt.Println("function bode begin")
	} else {
		panic("'(' is required")
	}
	function.Clauses = code.CollectClauses()
	//结束函数体
	return function
}

//解析独立子句，包括赋值号、逗号、各种运算符和圆括号。不包括for、if-else、def之类的关键词
func (code *DrCode) ParseClause2() *DrClause {
	var result *DrClause
	result = new(DrClause)
	result.ClauseType = ClauseType_SINGLE

	formula := make([]*DrClause, 0, 20)
	var token string
	//i := start
	//	count := 0
	var pair *DrClause
	count := 0 //用于对冒号出现的状态记数，当遇到一个冒号时count+1，遇到一个逗号且count>0时count-1
	for {
		if len(code.tokenList) <= 0 {
			break
		}
		token = code.tokenList[0]
		if token == "\n" || token == "{" || token == "}" {
			cl0 := HandleFormula(formula)
			result.AddParameter(cl0)
			result = upgradeClause(result)

			return result
		}
		token := code.TokenForward()
		// if token == "," { //解析后续的参数，加入已有的clause
		// 	//先把前面收集到的formula解析后，再解析','之后的内容
		// 	cl0 := HandleFormula(formula)
		// 	result.AddParameter(cl0) //与逗号后面的内容是并列的
		// 	//fmt.Print("遇到了逗号，已将逗号前面的表达式处理过了，如：")
		// 	//			printFormula(formula)
		// 	formula = []*DrClause{}
		// 	continue
		// }
		if token == "," { //解析后续的参数，加入已有的clause
			//先把前面收集到的formula解析后，再解析','之后的内容
			cl0 := HandleFormula(formula)
			if count > 0 { //凡是前面有没处理完的冒号，进入这里处理
				//fmt.Println(count, token, tokenList, pair)
				pair.parameters = append(pair.parameters, cl0)
				count -= 1
				if len(pair.parameters) != 2 {
					panic("incorrect Pair")
				}
				result.AddParameter(pair)
			} else { //不涉及冒号的这样处理
				result.AddParameter(cl0)
			}
			//与逗号后面的内容是并列的
			//fmt.Print("遇到了逗号，已将逗号前面的表达式处理过了，如：")
			//			printFormula(formula)
			formula = []*DrClause{}
			continue
		}
		if token == ":" { //解析后续的参数，加入已有的clause
			//先把前面收集到的formula解析后，再解析','之后的内容
			pair = new(DrClause)
			pair.funcName = "pair"
			pair.ClauseType = ClauseType_SINGLE
			cl0 := HandleFormula(formula)
			pair.parameters = append(pair.parameters, cl0)
			count += 1
			//result.AddParameter(cl0) //与逗号后面的内容是并列的
			//fmt.Print("遇到了逗号，已将逗号前面的表达式处理过了，如：")
			//			printFormula(formula)
			formula = []*DrClause{}
			continue
		}
		if token[0] == '.' && IsValidVarName(token[1:]) && code.tokenList[0] == "(" {
			code.TokenForward()
			code.bStack.push(Type_FuncCall)
			clause := code.ParseClause2()
			cl := new(DrClause)
			cl.ClauseType = ClauseType_SINGLE
			cl.funcName = token
			n := len(formula)
			cl.AddParameter(formula[n-1])                               //把前面formula中的最后一项(即所属module或所属对象)作为当前clause的第一个参数
			cl.parameters = append(cl.parameters, clause.parameters...) //把clause收集到的参数当作其它参数
			formula[n-1] = cl
			continue
		}
		if token[0] == '.' && IsValidVarName(token[1:]) {
			code.TokenForward()

			cl := new(DrClause)
			cl.ClauseType = ClauseType_VAR
			cl.funcName = token
			n := len(formula)
			cl.AddParameter(formula[n-1]) //把前面formula中的最后一项(即所属module或所属对象)作为当前clause的第一个参数
			formula[n-1] = cl             //把新建的clause添加到formula末尾，只不过不带其它参数了
			continue

		}

		if IsValidVarName(token) && code.tokenList[0] == "(" { //遇到 funcname(),处理至下一个")",在函数内部新建一个clause并赋好参数，出来时赋函数名称
			//fmt.Println("现在开始进入新函数的调用了:", tokens[i], tokens[i+1])
			code.bStack.push(Type_FuncCall)
			code.TokenForward()
			clause := code.ParseClause2() //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
			clause.funcName = token
			//fmt.Println("本层函数调用结束：", clause.funcname)
			formula = append(formula, clause)
			continue
		}
		//var clause *Clause
		if token == "(" { //'('表明开始了一个新的调用，从当前括号‘(’开始到下一个‘)’结束，找到若干个逗号分隔的clause，共同作为当前调用的参数
			//fmt.Println("现在开始进入新括号的调用了:", tokens[i], tokens[i+1])
			code.bStack.push(Type_Clause)
			clause := code.ParseClause2() //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
			clause = upgradeClause(clause)
			//fmt.Println("本层括号调用结束：", clause.funcname, i, tokens[i])
			formula = append(formula, clause)
			// continue
		}
		if token == ")" { //遇到递归返回标志了  ，但是分两种情况
			top := code.bStack.pop()
			if top == Type_Clause { //如果是普通括号，返回值 是一个直接的clause
				//printFormula(formula)
				cls := HandleFormula(formula)
				result.AddParameter(cls)
			} else {
				//如果是带函数的括号，返回值是作为函数的其中一个参数
				if len(formula) > 0 {
					//printFormula(formula)
					//					result.print()
					cl := HandleFormula(formula)
					//					cl.print()
					if count > 0 { //凡是前面有没处理完的冒号，进入这里处理
						//fmt.Println(count, token, tokenList, pair)
						pair.parameters = append(pair.parameters, cl)
						count -= 1
						if len(pair.parameters) != 2 {
							panic("incorrect Pair")
						}
						result.AddParameter(pair)
					} else { //不涉及冒号的这样处理
						result.AddParameter(cl)
					}
					//					result.print()
				}
			}
			//i += 1
			//fmt.Println("现在要从", tokens[i], "返回上级，下一个符号是", tokens[i+1], "现在所在的函数看下面吧")
			if IsNumber(result.funcName) && result.ClauseType == ClauseType_VAR {
				panic("clause type incorrect")
			}
			return result
		}
		if token == "=" {
			cl := HandleFormula(formula) //把等号之前收集好的公解析为clause
			result.AddParameter(cl)      //把解析好的clause把为参数添加到result中
			result = upgradeClause(result)
			if result.funcName == "getItem" {
				result.funcName = "setItem"
				cl2 := code.ParseClause2()
				result.AddParameter(cl2)
			} else {
				temp := result
				result = new(DrClause) //使用新建的result
				result.ClauseType = ClauseType_SINGLE
				result.AddParameter(temp)
				result.funcName = "assign"
				cl2 := code.ParseClause2()
				result.AddParameter(cl2)
			}
			return result
		}
		if IsOperator(token) { //如果是这种情况，就需要扫描后续的同括号内的表达式
			cl := new(DrClause)
			cl.ClauseType = ClauseType_VAR
			cl.setVariable(token)
			formula = append(formula, cl)
			continue
		}
		if IsNumber(token) {
			//			fmt.Println("enter_5:", tokens[i])
			cl := new(DrClause)
			cl.setConstant(token)
			formula = append(formula, cl)
			continue
		}
		if IsValidVarName(token) {
			cl := new(DrClause)
			cl.ClauseType = ClauseType_VAR
			cl.setVariable(token)
			//			cl.print()
			formula = append(formula, cl)
			//printFormula(formula)

			//			fmt.Println("-", i, "-", len(tokens), "-", tokens[i])
			continue
		}

		if token == "'" || token == "\"" {
			cl := new(DrClause)

			cl.Type = TypeString
			cl.ClauseType = ClauseType_CONSTANT
			str0 := code.TokenForward()
			cl.Type = TypeString
			cl.Value = str0
			cl.funcName = str0
			sss := code.TokenForward()
			if sss != token {
				panic("A quotation mark is required, but encountered a " + sss)
			}
			formula = append(formula, cl)
			continue
		}
		if token == "[" {

			tokenList2 := cutSquarePair(code.tokenList)

			code.tokenList = code.tokenList[len(tokenList2)+1:]
			//fmt.Println("cutPair", code.tokenList, "tokenList2=", tokenList2)

			opCL := new(DrClause) //放置符号[]的clause
			opCL.ClauseType = ClauseType_VAR
			opCL.setVariable("[]")
			formula = append(formula, opCL)
			//opCL.Print()
			//fmt.Println()
			//fmt.Println("tokenList2:", tokenList2, "opCL=", opCL)
			tempCL, _ := code.ParseClause1(tokenList2) //放置下标的clause
			//fmt.Println(tokens2)
			formula = append(formula, tempCL)
			//panic("未完成，请补代码")
			continue
		}

		if token == "\n" {
			//fmt.Println("\n is encountered")
			break
		}
	}
	//panic("Wrong exit")
	r := HandleFormula(formula)
	if IsNumber(r.funcName) && r.ClauseType == ClauseType_VAR {
		panic("clause type incorrect")
	}
	//	r.Print()
	return r
}

//找到换行符之前的字符串，以及下一行的起始下标
func (code *DrCode) GetLine(tokens []string) ([]string, int) {

	pos := 0
	for i := 0; i < len(tokens); i++ {
		if tokens[i] == "\n" { //遇到下一个换行符时结束
			pos = i //位置指向换行符
			break
		}
	}
	return tokens[0:pos], pos + 1
}
func (code *DrCode) processFor(tokens []string) *DrClause {
	varName := code.TokenForward()
	if !(IsValidVarName(varName) && !InKeywords(varName)) {
		panic("A variable name is required after the 'for'")
	}
	token := code.TokenForward() //必须是in才行
	if token != "in" {
		panic("must be 'in' here,but got a " + token)
	}

	//处理for迭代依赖的迭代器子句
	clause := code.ParseClause2()
	clause.Print()
	fmt.Println()
	//创建for子句，将迭代器子句加入条件
	forClause := NewClauseFOR()
	forClause.returnName = varName
	forClause.parameters = append(forClause.parameters, clause)

	//code.tokenList = code.tokenList[pos:]
	token = code.TokenForward()
	for { //绕过那些换行符
		if token == "\n" {
			token = code.TokenForward()
		} else {
			break
		}
	}
	if token != "{" {
		panic("A '{' is required here, but " + varName + " is encountered")
	}
	//进入了for内部
	//fmt.Println("进入了for内部")
	forClause.subClauseA = code.CollectClauses()
	//fmt.Println("for clauses ended")
	//function.AddClause3(forClause)
	return forClause
}
func (code *DrCode) processWhile(tokens []string) *DrClause {

	//处理while迭代依赖的迭代器子句
	clause := code.ParseClause2()
	clause.Print()
	fmt.Println()
	//创建for子句，将迭代器子句加入条件
	whileClause := NewClauseWHILE()
	whileClause.parameters = append(whileClause.parameters, clause)

	//code.tokenList = code.tokenList[pos:]
	token := code.TokenForward()
	for { //绕过那些换行符
		if token == "\n" {
			token = code.TokenForward()
		} else {
			break
		}
	}
	if token != "{" {
		panic("A '{' is required here, but " + token + " is encountered")
	}
	//进入了while内部
	//fmt.Println("进入了while内部")
	whileClause.subClauseA = code.CollectClauses()
	//fmt.Println("while clauses ended")
	//function.AddClause3(forClause)
	return whileClause
}
func (code *DrCode) processIf(tokens []string) *DrClause {
	ifClause := NewClauseIF()

	//处理条件语句
	clause := code.ParseClause2()
	//code.tokenList = code.tokenList[pos:]
	clause.Print()
	ifClause.parameters = append(ifClause.parameters, clause)
	varName := code.JumpLines()

	if varName != "{" {
		panic("A '{' is required here, but " + varName + " is encountered")
	}
	code.TokenForward()
	//fmt.Println("Enter the if statement")
	ifClause.subClauseA = code.CollectClauses()

	//fmt.Println("If clauses ended")
	varName = code.JumpLines()
	if varName != "else" {
		return ifClause
	}
	code.TokenForward()
	//fmt.Println("已进入else子句内")
	token := code.JumpLines()
	if token != "{" {
		panic("A '{' is required here, but " + token + " is encountered")
	}
	code.TokenForward()
	ifClause.subClauseB = code.CollectClauses()
	token = code.TokenForward()
	//fmt.Println("else clause ended:", token)

	// if !(IsValidVarName(varName) && !InKeywords(varName)) {
	// 	panic("A variable name is required after the 'for'")
	// }
	// token := code.TokenForward() //必须是in才行
	// if token != "in" {
	// 	panic("must be 'in' here,but got a " + token)
	// }
	//处理for迭代依赖的迭代器
	return ifClause
}
func (code *DrCode) JumpLines() string {
	//name := code.tokenList[0] // code.TokenForward()
	var name string
	for {
		if len(code.tokenList) == 0 {
			name = ""
			break
		}
		name = code.tokenList[0]
		if name == "\n" {
			code.TokenForward()
		} else {
			break
		}

	}
	return name
}

//处理子句序列(不包括函数声明)
func (code *DrCode) CollectClauses() []*DrClause {
	clauses := make([]*DrClause, 0, 10)
	//每循环一趟，处理一条行子句，直至处理完所有
	for {
		if len(code.tokenList) == 0 {
			break
		}
		//搜索下一个标识符，判断是变量名还是关键词
		//跳过所有空行
		//i := 0
		name := code.tokenList[0]
		if name == "\n" {
			code.TokenForward()
			continue
		}
		if name == "def" || name == "import" {
			break
		}

		if (IsValidVarName(name) || IsNumber(name)) && !InKeywords(name) { //如果新读入的是一个变量名，则按照子句对待
			if len(code.tokenList) <= 0 {
				break
			}
			//fmt.Println(name, "进入ParseClause2")
			clauseSimple := code.ParseClause2()
			//clauseSimple.Print()
			//fmt.Println("已退出ParseClause2")
			//function.AddClause3(clause)
			clauses = append(clauses, clauseSimple)
			//code.tokenList = code.tokenList[nextLineIndex:]
		} else if name == "return" {
			code.TokenForward()
			line, pos := code.GetLine(code.tokenList)
			var returnVar *DrClause
			if len(line) == 0 {
				returnVar = nil
			} else {
				returnVar, line = code.ParseClause1(line)
			}
			code.tokenList = code.tokenList[pos:]
			//function.returnVarNames = []string{returnVar}
			//fmt.Println("return:", returnVar, pos)
			//不要忘了这一块.....................
			clause := new(DrClause)
			clause.funcName = "return"
			clause.ClauseType = ClauseType_SINGLE
			clause.AddParameter(returnVar)
			clauses = append(clauses, clause)
			//处理返回值
		} else if name == "}" {
			//fmt.Println("---------end", name)
			code.TokenForward()
			break
		} else if name == "for" {
			//fmt.Println("For clause started")
			code.TokenForward()
			clauseFor := code.processFor(code.tokenList)
			clauses = append(clauses, clauseFor)
			//break
		} else if name == "if" {
			//fmt.Println("If clause started")
			code.TokenForward()
			clauseIf := code.processIf(code.tokenList)
			clauses = append(clauses, clauseIf)
		} else if name == "continue" || name == "break" {
			clause := new(DrClause)
			clause.funcName = name
			code.TokenForward()
			clauses = append(clauses, clause)
		} else if name == "while" {
			code.TokenForward()
			clauseFor := code.processWhile(code.tokenList)
			clauses = append(clauses, clauseFor)
		} else {
			panic("something error")
		}

	}

	return clauses
}
